{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 施磊: 手写C++ Muduo网络库项目-掌握高性能网络库实现原理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 两阶段模型：数据准备 & 数据读写"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 阶段                  | 关注点                          | 常见系统调用                                                 | 关键词             |\n",
    "| --------------------- | ------------------------------- | ------------------------------------------------------------ | ------------------ |\n",
    "| **Phase 1：数据准备** | 内核判断数据是否已经到达        | `select` / `poll` / `epoll_wait`、阻塞式 `accept`/`recv`     | **阻塞 vs 非阻塞** |\n",
    "| **Phase 2：数据读写** | 真正的数据拷贝（内核 ↔ 用户态） | `recv` / `read` / `write`、`sendfile`、`aio_read`、`io_uring_enter` | **同步 vs 异步**   |\n",
    "\n",
    "> 口诀：**阻塞/非阻塞**关心“你怎么向内核打听数据到了没”；**同步/异步**关心“谁搬数据、什么时候告诉你”。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 阻塞 vs 非阻塞（Phase 1 视角）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "核心对比\n",
    "\n",
    "| 维度           | 阻塞 I/O（Blocking I/O）                                     | 非阻塞 I/O（Non-blocking I/O）                               |\n",
    "| -------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |\n",
    "| 模型定义与流程 | 默认 socket 为阻塞模式。无数据时调用 `read/recv` 的线程睡眠，直到数据到达并从内核缓冲区拷贝到用户缓冲区。 | 通过 `fcntl` 或 `setsockopt(fd, SOL_SOCKET, SO_NONBLOCK)` 设置为非阻塞。无数据时 `read/recv` 立即返回 `-1`，置 `errno=EAGAIN/EWOULDBLOCK`。 |\n",
    "| 线程状态       | 调用期间线程睡眠，需等待内核唤醒。                           | 系统调用立即返回，线程保持就绪，可继续执行其他逻辑。         |\n",
    "| 无数据时行为   | 线程被挂起，等待内核缓冲区有数据后唤醒。                     | 立即返回错误码，交由上层逻辑决定下一步处理。                 |\n",
    "| CPU 占用       | 阻塞等待阶段几乎为 0。                                       | 视上层策略而定；结合 I/O 复用可避免忙轮询。                  |\n",
    "| 编程复杂度     | 顺序执行，逻辑简单。                                         | 需事件循环或状态机管理，复杂度较高。                         |\n",
    "| 优缺点         | **优点**：实现简单；逻辑直观。<br>**缺点**：等待与拷贝阶段均阻塞，一线程一连接，扩展性差。 | **优点**：线程不挂起，可处理其他任务。<br>**缺点**：不配合事件驱动易忙轮询；实现更复杂。 |\n",
    "| 本质           | 同步 I/O，数据拷贝由调用线程完成，且等待阶段阻塞。           | 同步 I/O，数据拷贝仍由调用线程完成，只是等待阶段不阻塞。     |\n",
    "| 典型场景       | 少量连接、脚本式程序、阻塞线程池。                           | 高并发服务器、Reactor 模型、需高伸缩性的异步框架。           |\n",
    "| 示例文件       | [blocking_echo_server.cpp](./blocking_echo_server.cpp)                                    | [nonblocking_epoll_server.cpp](./nonblocking_epoll_server.cpp)                                 |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "执行步骤\n",
    "\n",
    "| 步骤 | 阻塞 I/O（Blocking I/O）     | 非阻塞 I/O（Non-blocking I/O）                               |\n",
    "| ---- | ---------------------------- | ------------------------------------------------------------ |\n",
    "| 1    | 应用调用 `read/recv`。       | 调用 `read/recv`。                                           |\n",
    "| 2    | 内核检查 TCP 接收缓冲区。    | 内核检查 TCP 接收缓冲区。                                    |\n",
    "| 3    | 若无数据，线程阻塞等待。     | 若无数据，立即返回 `-1` 并置 `errno=EAGAIN/EWOULDBLOCK`。    |\n",
    "| 4    | 数据到达后，内核唤醒线程。   | 上层逻辑循环重试，或配合 I/O 复用等待事件通知；数据到达后获得通知。 |\n",
    "| 5    | 内核将数据拷贝到用户缓冲区。 | 内核将数据拷贝到用户缓冲区。                                 |\n",
    "| 6    | `read` 返回，应用继续处理。  | `read` 返回，应用继续处理。                                  |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "工程要点\n",
    "\n",
    "- **阻塞模式**（默认）：\n",
    "  - `recv` 没数据 → 线程睡眠 → 内核唤醒时返回。\n",
    "  - 优点：实现简单；缺点：1 线程/连接，扩展性差。\n",
    "- **非阻塞模式**：\n",
    "  - 通过 `fcntl(sockfd, F_SETFL, O_NONBLOCK)` 或 `SetNonBlocking` 自封函数开启。\n",
    "  - 必须配合 `epoll/poll/select` 等多路复用，避免忙轮询。\n",
    "  - 若处理不当（无事件驱动）会耗尽 CPU。\n",
    "  - 线程始终可运行，需要应用层安排“下一次尝试”时机。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 同步 vs 异步（Phase 2 视角）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同步 IO\n",
    "\n",
    "- **定义**：数据从内核缓冲区拷贝到用户缓冲区的过程由调用线程亲自完成。\n",
    "- **例子**：`recv`、`read`、`write`（无论阻塞还是非阻塞，都是同步 IO）。\n",
    "- **特点**：\n",
    "  - 调用期间线程要么阻塞等待，要么忙等/反复调用直到拷贝完成。\n",
    "  - IO 耗时体现在调用时长；程序员负责管理缓冲区、解析协议。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "异步 IO（真正的 OS 级别 AIO）\n",
    "\n",
    "- **定义**：应用发起请求后立即返回，内核在后台完成拷贝，再通过事件/回调通知应用。\n",
    "- **典型 API**：\n",
    "  - Linux：`io_submit`（libaio）、`io_uring_enter`、`aio_read`。\n",
    "  - Windows：IOCP、`ReadFileEx`、`WSARecv` with completion port。\n",
    "- **流程**：\n",
    "  1. 提交请求（不阻塞）。\n",
    "  2. 内核异步完成数据搬运。\n",
    "  3. 通过事件队列 / 信号 / 回调告知结果。\n",
    "- **优势**：减少线程数量、降低上下文切换；对高性能系统尤为重要。\n",
    "- **挑战**：API 复杂度高，调试难度大；需要内核支持（如 Linux 5.1+ 的 io_uring）。\n",
    "\n",
    "> **陈硕观点**：阻塞 IO 与非阻塞 IO 仍然属于同步 IO，因为数据拷贝都发生在调用线程上下文中。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "同步/异步差异速览\n",
    "\n",
    "| 指标     | 同步 IO                      | 异步 IO                                |\n",
    "| -------- | ---------------------------- | -------------------------------------- |\n",
    "| 调用方式 | `recv()` 阻塞或循环直到完成  | `aio_read()` 提交后立即返回            |\n",
    "| 数据搬运 | 调用线程在用户态完成         | 内核后台完成，应用收到通知时数据已就绪 |\n",
    "| CPU 消耗 | 调用期间被占用（阻塞或忙等） | 调用线程可去做其他任务                 |\n",
    "| 编程成本 | 接口简单                     | 需准备 `aiocb`、注册通知等，调试难度高 |\n",
    "| 典型类比 | 自己去机场取票               | 快递送票上门                           |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# `recv` 函数详述与返回值处理"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "函数签名"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "vscode": {
     "languageId": "cpp"
    }
   },
   "outputs": [],
   "source": [
    "ssize_t recv(int sockfd, void *buf, size_t len, int flags);"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "返回值语义（涵盖阻塞/非阻塞）\n",
    "\n",
    "| 返回值    | 含义                     | 处理建议                      |\n",
    "| --------- | ------------------------ | ----------------------------- |\n",
    "| `n > 0`   | 成功读取 `n` 字节        | 继续解析协议或写入业务缓冲区  |\n",
    "| `n == 0`  | 对端有序关闭（FIN）      | 关闭本端 socket，清理会话资源 |\n",
    "| `n == -1` | 发生错误，需查看 `errno` | 见下方错误码分支              |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "常见 `errno` 分支\n",
    "\n",
    "| errno / 标记                                 | 含义                                 | 处理建议                                    | 备注                                    |\n",
    "| -------------------------------------------- | ------------------------------------ | ------------------------------------------- | --------------------------------------- |\n",
    "| `EAGAIN` / `EWOULDBLOCK`                     | 非阻塞套接字当前无数据可读           | 忽略本次结果，等待下一次 `epoll` 等事件通知 | 两者数值相同，判断其一即可              |\n",
    "| `EINTR`                                      | 系统调用被信号中断                   | 重新调用 `recv`，直到成功或出现其他错误     | 常在信号触发时出现                      |\n",
    "| `ECONNRESET`                                 | 对端异常断开（发送 RST）             | 关闭 socket，记录日志                       | 典型的非正常关闭场景                    |\n",
    "| `EBADF` / `ENOTCONN`                         | 文件描述符非法或套接字尚未连接       | 检查程序逻辑、套接字生命周期管理            | 代码缺陷导致，多出现在调试阶段          |\n",
    "| `EFAULT`                                     | 用户缓冲区指针越界                   | 修复代码，保证缓冲区合法                    | 属于程序员错误                          |\n",
    "| `MSG_TRUNC` / `MSG_CTRUNC` *(recvmsg flags)* | 数据报或控制信息被截断（缓冲区太小） | 增大缓冲区或处理截断逻辑                    | 由 `recvmsg` 返回的辅助信息，不是 errno |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [nonblocking_epoll_server.cpp](./nonblocking_epoll_server.cpp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 四象限：阻塞/非阻塞 × 同步/异步"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| Phase 2 \\ Phase 1 | **阻塞**                                           | **非阻塞**                                                   |\n",
    "| ----------------- | -------------------------------------------------- | ------------------------------------------------------------ |\n",
    "| **同步**          | 经典阻塞 `recv` / `accept`（线程睡眠直到拷贝结束） | `O_NONBLOCK + recv`：无数据返回 `EAGAIN`，需要事件循环重试。两者都由线程搬数据。 |\n",
    "| **异步**          | 基本不存在（因为异步本就不应阻塞等待通知）         | POSIX AIO、`io_uring`、Windows IOCP：提交请求即返回，内核完成后通知。 |\n",
    "\n",
    "> 常见误区：把“非阻塞”误认为“异步”。**非阻塞只是同步 IO 的一种实现方式**。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Linux 五类 IO 模型概览（UNIX 网络编程经典分类）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 型                     | 相对位置 | 描述                                                | 代表实现                            |\n",
    "| ---------------------- | -------- | --------------------------------------------------- | ----------------------------------- |\n",
    "| 阻塞 IO                | 最早     | 调用阻塞直到数据准备好并完成拷贝                    | `blocking recv`                     |\n",
    "| 非阻塞 IO              | 提升     | 不等待直接返回，需要应用程序轮询                    | `O_NONBLOCK + recv`                 |\n",
    "| IO 多路复用（Reactor） | 常用     | 通过 `select/poll/epoll` 等在多个 fd 间等待数据就绪 | muduo（LT）、libevent、Netty        |\n",
    "| 信号驱动 IO            | 较少用   | `SIGIO` 告知数据到达，随后应用主动读取              | `fcntl(F_SETOWN)` + signal          |\n",
    "| 异步 IO（Proactor）    | 高级     | 内核完成数据复制后通知应用，应用直接消费            | `io_uring`, Windows IOCP, POSIX AIO |\n",
    "\n",
    "> **工程实践**：`epoll` + 线程池通常优于 `epoll` + 进程池，原因是线程切换低成本、共享内存无需额外 IPC。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# IO 多路复用与事件驱动"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 通过 `select`、`poll`、`epoll_wait` 监控多个 fd。将“等待数据就绪”阶段外包给内核的复用器，同时管理大量连接。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`epoll` 工作原理概览\n",
    "\n",
    "- **LT（Level Trigger）**：只要内核缓冲区未读空就持续触发；安全但事件可能频繁。\n",
    "- **ET（Edge Trigger）**：状态变化才触发（如从“无数据”变“有数据”），需一次读空缓冲区，否则丢事件。\n",
    "- **优势**：相较 `select`/`poll`，`epoll` 在海量 fd 场景下更高效。适合与非阻塞套接字组合。\n",
    "\n",
    "触发条件\n",
    "- LT: `ev.events = EPOLLIN;`（默认不加 `EPOLLET`）,  `epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);`\n",
    "- ET: `ev.events = EPOLLIN | EPOLLET;` , `epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);` "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "select / poll / epoll 对比\n",
    "\n",
    "| 接口     | 优点                                                       | 不足                                       |\n",
    "| -------- | ---------------------------------------------------------- | ------------------------------------------ |\n",
    "| `select` | 跨平台                                                     | fd 数量有限、每次调用需拷贝整个 fd 集      |\n",
    "| `poll`   | 无数量上限                                                 | 每次线性扫描，仍有 O(n) 复杂度             |\n",
    "| `epoll`  | 几乎 O(1)，就绪列表 + 回调架构、支持 EPOLLEXCLUSIVE 降惊群 | Linux 特有，语义较复杂（LT/ET/ONESHOT 等） |"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在高性能服务器中的价值\n",
    "\n",
    "- 单线程可管理成千上万个连接，避免“一连接一线程”。\n",
    "- 常见模式：**Reactor = 非阻塞 fd + epoll (LT/ET) + 状态机**。\n",
    "- 工程实践：\n",
    "  - I/O 线程仅负责事件循环。\n",
    "  - 业务逻辑或 CPU 密集任务交给线程池。\n",
    "  - 合理处理超时、优雅关闭、`EPOLLEXCLUSIVE` 等细节以防惊群。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "典型 Reactor 流程\n",
    "\n",
    "1. `epoll_wait` 等待就绪事件（阻塞或超时）。\n",
    "2. 对于监听 fd：循环 `accept` 直到返回 `EAGAIN`。\n",
    "3. 对于连接 fd：循环 `recv` 直到返回 `EAGAIN`，处理业务逻辑。\n",
    "4. 可选：将耗时任务投递到线程池，避免阻塞事件循环。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- [nonblocking_epoll_server.cpp](./nonblocking_epoll_server.cpp)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 信号驱动 I/O（Signal-Driven I/O）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "工作方式\n",
    "\n",
    "1. 使用 `fcntl(F_SETOWN)` 和 `sigaction` 注册 `SIGIO` 处理器。\n",
    "2. 内核在数据就绪时发 SIGIO 信号通知。\n",
    "3. 应用在信号处理函数或主循环中调用 `read/recv` 完成数据拷贝。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "特点\n",
    "\n",
    "- **第一阶段（数据就绪通知）**：异步，通过信号通知应用，无需阻塞或轮询。\n",
    "- **第二阶段（数据拷贝）**：仍需应用线程亲自执行，属于同步。\n",
    "- **优势**：减少轮询系统调用次数，CPU 利用率更高。\n",
    "- **劣势**：信号语义复杂，调试困难，适用于特定场景（如特殊设备、实时系统）。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 异步 IO 接口详解（POSIX AIO & io_uring）"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "POSIX AIO（`aio_read` / `aio_write`）\n",
    "\n",
    "- 链接 `-lrt`。\n",
    "- `struct aiocb` 关键字段：\n",
    "  - `aio_fildes`（文件描述符）\n",
    "  - `aio_buf`（用户缓冲区指针）\n",
    "  - `aio_nbytes`（字节数）\n",
    "  - `aio_offset`（偏移）\n",
    "  - `aio_sigevent`（通知机制配置）\n",
    "  - `aio_reqprio`（优先级）\n",
    "- 工作流程：提交请求（立即返回）→ 内核后台搬运 → `SIGEV_SIGNAL` / `SIGEV_THREAD` 通知 → 通过 `aio_error` / `aio_return` 获取结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "`io_uring`（Linux 5.1+）\n",
    "\n",
    "- 高性能异步 IO 框架，采用共享 ring buffer 与 SQ/CQ（提交/完成队列）。\n",
    "- 相对 POSIX AIO 更统一、更高效；支持网络 IO、文件 IO 混合。\n",
    "- 典型流程：`io_uring_queue_init` → 填充 SQE → `io_uring_submit` → 事件循环中 `io_uring_wait_cqe` 获取完成。\n",
    "\n",
    "> 实战建议：在业务中引入异步 IO 前需评估 API 复杂度与运维成本；调试异步程序难度显著高于同步模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Node.js 与业务层异步模型"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **事件驱动 + 非阻塞 + 回调**：所有 IO 操作提交后立即返回，由 libuv 线程池或 `epoll` 管理事件。\n",
    "- **特点**：通过回调/Promise 处理结果，避免主线程阻塞，适合 IO 密集型服务。\n",
    "- **注意**：Node.js 自身的事件循环仍需要底层同步/异步原语（比如 `epoll`、线程池、`uv_fs_read`）。\n",
    "- **回调地狱问题**：可用 Promise/async-await 改善，但本质仍是异步事件通知。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 高性能服务器常见方案"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Epoll + 线程池**\n",
    "\n",
    "- 每个线程一个事件循环，线程数通常与 CPU 核心数相当。\n",
    "- Muduo、Netty 常用此模式。\n",
    "\n",
    "**Epoll + fork（多进程）**\n",
    "\n",
    "- Nginx 的经典架构。\n",
    "- 借助负载均衡策略（如 accept_mutex 等“乐观锁”）缓解进程惊群。\n",
    "\n",
    "**选型建议**\n",
    "\n",
    "- 需根据业务特点选择合适模型，而非单纯比较绝对性能。\n",
    "- 考虑部署环境、线程/进程管理成本及运维复杂度。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 操作系统层与业务层“同步/异步”区别"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 层面             | “同步/异步”含义              | 实例                                           |\n",
    "| ---------------- | ---------------------------- | ---------------------------------------------- |\n",
    "| **OS / IO 模型** | 内核是否负责搬数据并主动通知 | 阻塞/非阻塞 `recv`（同步）、`io_uring`（异步） |\n",
    "| **业务逻辑**     | 任务之间是否等待 / 使用回调  | 线程池任务、Future、Actor、Node.js 事件循环    |\n",
    "\n",
    "- Reactor：同步 IO + 事件驱动（应用层自己搬数据）。\n",
    "- Proactor：异步 IO + 回调通知（内核搬数据，应用消费结果）。\n",
    "- 业务层异步（如 async/await）并不等同于 OS 层异步。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 模型选型与工程实践建议"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- **阻塞 + 线程池**：简单易实现，小型项目首选。\n",
    "- **非阻塞 + epoll**：高并发的主流模式，配合线程池实现 I/O 与计算分离。\n",
    "- **信号驱动/异步 I/O**：在特定场景或追求极致性能时使用，需要高工程能力。\n",
    "- **`EPOLLEXCLUSIVE`**：适用于监听 socket，降低惊群效应（多个等待线程同时被唤醒却只有一个能成功 `accept` 的“惊群”情况）。\n",
    "- **日志与度量**：记录异常 errno、单次 I/O 耗时，便于诊断。\n",
    "- **缓冲策略**：流式协议可使用环形缓冲；明确消息边界、避免粘"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 设计与调试建议"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **模式选择**：\n",
    "   - 少量连接 → 阻塞 + 线程池即可。\n",
    "   - 高并发 → 首选非阻塞 + `epoll`，必要时探索 `io_uring`。\n",
    "2. **避免忙轮询**：非阻塞必须配合事件通知。\n",
    "3. **正确处理 `EAGAIN`**：它代表“暂时无数据”，不是错误。\n",
    "4. **缓冲区设计**：\n",
    "   - 流式协议使用环形缓冲区；\n",
    "   - 明确消息边界（长度字段、分隔符等）。\n",
    "5. **日志与度量**：记录异常 `errno`、耗时，便于运维调优。\n",
    "6. **线程池配合**：IO 线程处理 `epoll`，工作线程负责 CPU 密集任务，实现 IO/计算分离。\n",
    "7. **学习路线**：\n",
    "   - 阶段式实现：阻塞 echo → 非阻塞 echo → `epoll` + Reactor → `io_uring` 实验。\n",
    "   - 阅读 muduo、libevent、libuv、Boost.Asio 源码理解工程级模式。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 面试/写作答题模板"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "1. **开篇**：说明 IO 分“数据准备”和“数据搬运”两阶段。\n",
    "2. **阐述阻塞/非阻塞**：从线程状态、CPU 占用、使用场景讲解。\n",
    "3. **再讲同步/异步**：突出“搬运责任”和“通知方式”，引入陈硕观点。\n",
    "4. **举例**：结合 `recv`、`epoll`、`aio_read`、Node.js 等说明。\n",
    "5. **错误处理**：重点强调 `EAGAIN/EWOULDBLOCK` 的正常性。\n",
    "6. **工程经验**：提到日志、缓冲、线程池、调试策略。\n",
    "7. **扩展**：可引申到 Reactor vs Proactor、`io_uring` 前景、业务层 async/await。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 重点易混淆总结"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "| 概念对比       | 正确认知                         | 常见误区                         |\n",
    "| -------------- | -------------------------------- | -------------------------------- |\n",
    "| 阻塞 vs 非阻塞 | 决定“等待数据准备”时线程是否睡眠 | 误以为非阻塞 = 异步              |\n",
    "| 同步 vs 异步   | 决定数据拷贝由谁完成、何时通知   | 将回调式框架误解为操作系统级异步 |\n",
    "| EAGAIN 语义    | 非阻塞下的“数据未到，请稍后”     | 错误地当成系统错误并关闭 socket  |\n",
    "| `size = -1`    | 需要 `errno` 判定分支            | 粗暴地把 `-1` 当成连接断开       |\n",
    "| 业务层异步     | 任务调度/回调/事件驱动           | 混淆为内核异步 IO                |\n",
    "\n",
    "------\n",
    "\n",
    "通过以上整理，可以把握网络 IO 领域的核心脉络：**两阶段模型 → 阻塞/非阻塞 → 同步/异步 → API 行为 → 工程实践**。配合文档（如 `man recv`、`man 7 epoll`）和源码阅读，你就能在实际项目中准确选择和实现合适的 IO 模型。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 推荐阅读 & 参考资料"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "- 《UNIX 网络编程（卷 1）》/《Linux 高性能服务器编程》\n",
    "- 《UNIX 环境高级编程》\n",
    "- 陈硕：《Linux 多线程服务端编程》、muduo 源码\n",
    "- `man 2 recv`, `man 7 epoll`, `man 7 aio`, `man 2 io_uring_enter`\n",
    "- libuv、Boost.Asio、Node.js 官方文档"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
